package com.hakim.wfb.customer.service.impl;

import com.hakim.wfb.bean.CreditPoint;
import com.hakim.wfb.bean.PointOrder;
import com.hakim.wfb.bean.RechargeRecord;
import com.hakim.wfb.bean.User;
import com.hakim.wfb.biz.CreditPointBiz;
import com.hakim.wfb.biz.PointOrderBiz;
import com.hakim.wfb.customer.enums.ErrorCodeEnum;
import com.hakim.wfb.customer.params.recharge.GetUserRechargeWebPageParameter;
import com.hakim.wfb.customer.params.recharge.WalletRechargeParameter;
import com.hakim.wfb.customer.params.wallet.GetCoinMarketPriceParam;
import com.hakim.wfb.customer.params.wallet.GetUserWalletParameter;
import com.hakim.wfb.customer.result.recharge.UserRechargeRecordView;
import com.hakim.wfb.customer.result.wallet.CoinMarketPriceResult;
import com.hakim.wfb.customer.result.wallet.UserWalletView;
import com.hakim.wfb.customer.service.RechargeService;
import com.hakim.wfb.customer.service.biz.TransactionBizService;
import com.hakim.wfb.customer.service.biz.TransPointBizService;
import com.hakim.wfb.dao.RechargeRecordDao;
import com.hakim.wfb.dao.UserDao;
import com.hakim.wfb.dao.UserWalletDao;
import com.hkfs.fundamental.api.data.ListResultEx;
import com.hkfs.fundamental.api.data.ObjectResultEx;
import com.hkfs.fundamental.api.data.ResultEx;
import com.hkfs.fundamental.exception.HkfsBizException;
import com.hkfs.fundamental.zookeeper.ZooKeeperClient;
import com.hkfs.fundamental.zookeeper.lock.ZookeeperLock;
import com.hakim.wfb.common.enums.PointTypeEnum;
import com.hakim.wfb.common.enums.RechargeStatusEnum;
import com.hakim.wfb.common.enums.TransTypeEnum;
import com.hakim.wfb.common.serial.SerialNoGenerator;
import com.hakim.wfb.common.serial.UUIDGenerator;
import com.hakim.wfb.common.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2017/8/4.
 */
@Service("rechargeService")
public class RechargeServiceImpl implements RechargeService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private TransactionBizService transBiz;

    @Autowired
    private CreditPointBiz creditPointBiz;

    @Autowired
    private PointOrderBiz pointOrderBiz;

    @Autowired
    private TransPointBizService transPointBizService;

    @Autowired
    private UserWalletDao userWalletDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private RechargeRecordDao rechargeRecordDao;

    @Resource
    @Qualifier("zkClient")
    private ZooKeeperClient zkClient;

    /**
     * 处理钱包上币回调通知
     *
     * @param param
     * @returns
     */
    @Override
    public ResultEx recharge(WalletRechargeParameter param) {

        ResultEx resultEx = new ResultEx();
        GetUserWalletParameter getUserWalletParameter = new GetUserWalletParameter();
        getUserWalletParameter.setWalletId(param.getUserid().longValue());
        List<UserWalletView> userWalletViewList = userWalletDao.getUserWallet(getUserWalletParameter);
        if (userWalletViewList.size() <= 0) {
            resultEx.makeFailedResult();
        }
        UserWalletView userWalletView = userWalletViewList.get(0);
        User user = userDao.getById(userWalletView.getUserId());
        if (user == null) {
            resultEx.setRetCode(ErrorCodeEnum.USER_NOT_EXIST_ERROR.getCode());
            resultEx.setRetMsg(ErrorCodeEnum.USER_NOT_EXIST_ERROR.getMessage());
            resultEx.makeFailedResult();
        }
        //获取久福币价格
        GetCoinMarketPriceParam getCoinMarketPriceParam = new GetCoinMarketPriceParam();
        ObjectResultEx<CoinMarketPriceResult> marketPriceResultObjectResultEx = transPointBizService
                .getCoinCurrentPrice(getCoinMarketPriceParam);
        if (marketPriceResultObjectResultEx.isFailed()) {
            resultEx.setRetCode(marketPriceResultObjectResultEx.getRetCode());
            resultEx.setRetMsg(marketPriceResultObjectResultEx.getRetMsg());
            return resultEx.makeFailedResult();
        }
        CoinMarketPriceResult coinMarketPriceResult = marketPriceResultObjectResultEx.getDataObject();
        if (coinMarketPriceResult == null) {
            return resultEx.makeFailedResult("积分提现异常,无法获取久福币价格");
        }

        CreditPoint creditPoint = creditPointBiz.getCreditPointById(user.getTid());
        if (creditPoint == null) {
            resultEx.setRetCode(ErrorCodeEnum.USER_CREDIT_POINT_NOT_EXIST_ERROR.getCode());
            resultEx.setRetMsg(ErrorCodeEnum.USER_CREDIT_POINT_NOT_EXIST_ERROR.getMessage());
            return resultEx.makeFailedResult();
        }

        BigDecimal pointAmount = param.getAmount().multiply(coinMarketPriceResult.getCurrentPrice());
        String orderNo = SerialNoGenerator.getRechargeOrderNo(user.getUserPhone());

        creditPoint.setCpElecPoint(creditPoint.getCpElecPoint() + pointAmount.doubleValue());
        int updateCount = creditPointBiz.update(creditPoint);
        if (updateCount <= 0) {
            throw new HkfsBizException(ErrorCodeEnum.CONCURRENT_MODIFY.getCode(), ErrorCodeEnum.CONCURRENT_MODIFY.getMessage());
        }

        RechargeRecord rechargeRecord = new RechargeRecord();
        rechargeRecord.setUserId(user.getTid());
        rechargeRecord.setPointType(PointTypeEnum.ELEC_POINT.getValue());
        rechargeRecord.setWalletId(param.getUserid().longValue());
        rechargeRecord.setWalletAddress(userWalletView.getWalletAddress());
        rechargeRecord.setOrderno(orderNo);
        rechargeRecord.setActualPoint(pointAmount);
        rechargeRecord.setPointAmount(pointAmount);
        rechargeRecord.setCoinAmount(param.getAmount());
        rechargeRecord.setCoinCode(coinMarketPriceResult.getCoinCode());
        rechargeRecord.setCoinPrice(coinMarketPriceResult.getCurrentPrice());
        Date now = new Date();
        rechargeRecord.setCreatedTime(now);
        rechargeRecord.setUpdatedTime(now);
        rechargeRecord.setRechargeDate(now);
        rechargeRecord.setRechargeStatus(RechargeStatusEnum.SUCCESS.getValue());
        rechargeRecordDao.add(rechargeRecord);

        //增加积分变动流水记录 用户为正数
        PointOrder pointOrder = new PointOrder();
        pointOrder.setTid(UUIDGenerator.getUUID());
        pointOrder.setPoAmount(creditPoint.getCpElecPoint());
        pointOrder.setPoCreateDate(DateUtils.getNow());
        pointOrder.setPoDescription(user.getTid() + "充值:" + param.getAmount().toString() + "，电子积分增加：" + pointAmount);
        pointOrder.setPoFromUser("0");
        pointOrder.setPoOrderno(orderNo);
        pointOrder.setPoPointType(PointTypeEnum.ELEC_POINT.getValue());
        pointOrder.setPoToUser(user.getTid());
        pointOrder.setPoTransPoint(pointAmount.doubleValue());
        pointOrder.setPoType(TransTypeEnum.RECHARGE.getValue());
        pointOrderBiz.add(pointOrder);

        //系统为负数
        PointOrder reversePointOrder = new PointOrder();
        reversePointOrder.setTid(UUIDGenerator.getUUID());
        reversePointOrder.setPoAmount(0);
        reversePointOrder.setPoCreateDate(DateUtils.getNow());
        reversePointOrder.setPoDescription(user.getTid() + "充值:" + param.getAmount().toString() + "，系统支出电子积分：-" + pointAmount);
        reversePointOrder.setPoFromUser(user.getTid());
        reversePointOrder.setPoOrderno(orderNo);
        reversePointOrder.setPoPointType(PointTypeEnum.ELEC_POINT.getValue());
        reversePointOrder.setPoToUser("0");
        reversePointOrder.setPoTransPoint(pointAmount.doubleValue() * -1);
        reversePointOrder.setPoType(TransTypeEnum.RECHARGE.getValue());
        pointOrderBiz.add(reversePointOrder);

        return resultEx.makeSuccessResult();
    }

    /**
     * @param parameter
     * @return
     */
    @Override
    public ListResultEx<UserRechargeRecordView> queryRechargeRecord(GetUserRechargeWebPageParameter parameter) {
        ListResultEx<UserRechargeRecordView> rechargeRecordViewListResultEx = new ListResultEx<>();
        rechargeRecordViewListResultEx.setDataList(rechargeRecordDao.queryRechargeRecord(parameter));
        rechargeRecordViewListResultEx.setTotalCount(rechargeRecordDao.countRechargeRecord(parameter));
        rechargeRecordViewListResultEx.setPageNo(parameter.getPageNo());
        rechargeRecordViewListResultEx.setPageSize(parameter.getPageSize());
        return rechargeRecordViewListResultEx.makeSuccessResult();
    }

    /**
     * 使用分布式锁 更新
     *
     * @param creditPoint
     * @return
     */
    private Integer updateCustomerOrderWithLock(CreditPoint creditPoint) {
        String lockPath = getOrderZKPath(creditPoint.getTid());
        ZookeeperLock lock = new ZookeeperLock(lockPath, zkClient);
        try {
            if (lock.tryLock(2000, TimeUnit.MILLISECONDS)) {

                return creditPointBiz.update(creditPoint);
            }
        } catch (InterruptedException e) {
            logger.error("获取分布式锁时抛错：", e);
        } finally {
            lock.unlock();
        }
        return 0;
    }

    private String getOrderZKPath(String orderUuid) {
        return "/cinema/schedule/ordersTimeOutJob/order_uuid_" + orderUuid;
    }
}
